﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ExchangeHog.MessageParser
{
	public class FieldNameToken : BaseToken
	{
		internal enum TokenType { NONE, SPACE, CRLF, COLON, FIELDNAME, EOF };
		internal TokenType TType { get; private set; }
		public String Repr { get; internal set; }
		internal int TokenTypeAsInt() { return (int)TType; }

		internal FieldNameToken(TokenType tt = TokenType.NONE, string repr = null) { TType = tt; Repr = repr; }

		internal void MarkAsCRLF() { TType = TokenType.CRLF; }
		internal void MarkAsSPACE() { TType = TokenType.SPACE; }

		internal bool IsSPACE() { return TType == TokenType.SPACE; }
	}

	public class FieldNameLexer : BaseLexer<FieldNameToken>
	{
		void ParseFieldName()
		{
			StringBuilder sb = new StringBuilder();

			if (!IsEndOfStream())
			{
				Char ch = PeekChar();

				while (!IsEndOfStream() && 32 < (short)ch && (short)ch < 127)
				{
					sb.Append(ch);
					SkipChar();
					if (!IsEndOfStream())
						ch = PeekChar();
				}
			}
			Tokens.Enqueue(new FieldNameToken(FieldNameToken.TokenType.FIELDNAME, sb.ToString()));
		} // end of ParseFieldName

		public FieldNameToken NextToken()
		{
			if (Tokens.Count == 0)
				do
					if (!IsEndOfStream())
					{
						Char ch = PeekChar();
						switch (ch)
						{
							case ':': SkipChar(); Tokens.Enqueue(new FieldNameToken(FieldNameToken.TokenType.COLON, Char.ToString(ch))); break;
							case '\t':
							case ' ': ParseLWS(); break;
							case '\r': ParseCRLF(); break;
							default:
								if (32 < (short)ch && (short)ch < 127)
									ParseFieldName();
								else
									throw new ApplicationException("Unexpected character '" + ch + "'");
								break;
						}
					}
					else
						Tokens.Enqueue(new FieldNameToken(FieldNameToken.TokenType.EOF));
				while (Tokens.Count == 0 && !IsEndOfStream());
			return Tokens.Dequeue();
		} // end of NextToken

		public FieldNameToken ParseThis(FieldNameToken.TokenType ttExpected)
		{
			return base.ParseThis(ttExpected);
		}

	}
}
